/*
 * Copyright (c) 2024 iSOFT INFRASTRUCTURE SOFTWARE CO., LTD.
 * easyAda is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *          http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */

#ifndef CORTEX_A55_TIMERS_H
#define CORTEX_A55_TIMERS_H

#include <plat/device.h>
#include <arch/utils.h>
#include <stdlib/stdint.h>
#include <core/handler.h>

#define GPT1_BASE               (DEVICE_VBASE_TIMER0)
#define MRS_CNTP_CTL_EL0(value) asm volatile("mrs %0,cntp_ctl_el0\n\t" : "=r"(value))
#define MSR_CNTP_CTL_EL0(value) asm volatile("msr cntp_ctl_el0,%0\n\t" ::"r"(value))
#define MRS_CNTPCT_EL0(value)   asm volatile("mrs %0,cntpct_el0\n\t" : "=r"(value))
extern uint32_t timer_frequency;
typedef struct {
    uint32_t LOAD_CONUNT0;
    uint32_t LOAD_CONUNT1;
    uint32_t CURRENT_VALUE0;
    uint32_t CURRENT_VALUE1;
    uint32_t CONTROL_REG;
    uint32_t reserve1;
    uint32_t INTSTATUS;
    uint32_t reserve2;
    uint32_t reserve[4];
    uint32_t CONTROL_REG2;
} TIMER_t;

extern TIMER_t *gpt;

static inline void pt_enable(void)
{
    uint64_t value;
    MRS_CNTP_CTL_EL0(value);
    value |= 0x01U;
    MSR_CNTP_CTL_EL0(value);
}
static inline void pt_disable(void)
{
    uint64_t value;
    MRS_CNTP_CTL_EL0(value);
    value &= ~(1U << 0);
    MSR_CNTP_CTL_EL0(value);
}
static inline void pt_enable_int(void)
{
    uint64_t value;
    MRS_CNTP_CTL_EL0(value);
    value &= ~(1U << 1);
    MSR_CNTP_CTL_EL0(value);
}
static inline void pt_disable_int(void)
{
    uint64_t value;
    MRS_CNTP_CTL_EL0(value);
    value |= (1U << 1);
    MSR_CNTP_CTL_EL0(value);
}
static inline void pt_ack_int(void)
{
}
static inline uint64_t pt_get_left(void)
{
    uint64_t value;
    MRS_CNTPCT_EL0(value);
    return value / (timer_frequency / 1000000U);
}
uint32_t           pt_set_next(uint64_t us_time);
extern void        gpt_init(void);
void               boottime_calculate(void);
static inline void pt_init(void)
{
    extern void irq_setup_handler(unsigned int irq, handler_t handler);
    extern void timer_handler(void);
    irq_setup_handler(IRQN_TIMER0, timer_handler);
    gpt_init();
}
#endif
